package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.CommentApi;
import com.tanhua.dubbo.api.MovementApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.VisitorsApi;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.dto.RecommendUserDto;
import com.tanhua.model.enums.CommentType;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.MovementsVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.VisitorsVo;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author: cl
 * @Date: 2022/5/4 - 05 - 04
 * @Description:
 */

/**
 * 朋友圈动态模块
 */
@Service
public class MovementService {

    //朋友圈服务
    @DubboReference
    private MovementApi movementApi;

    //上传图片到阿里云
    @Autowired
    private OssTemplate ossTemplate;

    //用户信息服务
    @DubboReference
    private UserInfoApi userInfoApi;

    //redis
    @Autowired
    private RedisTemplate<String, String> redis;

    @DubboReference
    private CommentApi commentApi;

    //访客服务
    @DubboReference
    private VisitorsApi visitorsApi;

    //冻结服务
    @Autowired
    private UserFreezeService userFreezeService;

    //mq消息服务
    @Autowired
    private MqMessageService mqMessageService;

    /**
     * 发布新动态
     *
     * @param movement
     * @param imageContent
     */
    public void send(Movement movement, MultipartFile[] imageContent) throws IOException {


        //查询是否被冻结
        userFreezeService.checkUserStatus(3, UserHolder.getUserId());

        //1、判断动态中是否有内容
        String textContent = movement.getTextContent();
        if (StringUtils.isEmpty(textContent)) {
            throw new BusinessException(ErrorResult.contentError());
        }
        //2、获取当前用户的id
        Long userId = UserHolder.getUserId();
        //3、遍历将文件上传到阿里云并获取到url
        List<String> medias = new ArrayList<>();
        for (MultipartFile multipartFile : imageContent) {
            InputStream inputStream = multipartFile.getInputStream();
            String originalFilename = multipartFile.getOriginalFilename();
            String url = ossTemplate.upload(originalFilename, inputStream);
            medias.add(url);
        }
        //4、将数据封装到Movement对象
        movement.setUserId(userId);
        movement.setMedias(medias);
        //5、调用服务发送
        String movementId = movementApi.send(movement);


        //发布完动态后发送mq消息后台利用阿里云进行审核
        mqMessageService.sendAudiMessage(movementId);
    }

    /**
     * 分页查询个人动态
     *
     * @param page
     * @param pageSize
     * @param userId
     * @return
     */
    public PageResult getByUserId(Integer page, Integer pageSize, Long userId) {

        //获取用户的id
        Long userid1 = UserHolder.getUserId();
        List<Movement> movements = new ArrayList<>();

        //判断用户的id和前端传过来的id是否一致(一致表示查询个人动态，不一致表示查询好友或者推荐好友动态)
        if (userid1 == userId) {
            //1、查询个人动态
            movements = movementApi.getByUserid(userId, page, pageSize);
        } else {
            //查询好友或者推荐好友动态
            movements = movementApi.getByFriendId(userid1, userId, page, pageSize);
        }
        //2、判断是否有动态，没有直接返回空
        if (CollUtil.isEmpty(movements)) {
            return new PageResult(page, pageSize, 0l, movements);
        }
        //3、查询个人信息
        UserInfo userInfo = userInfoApi.findById(userId);
        //4、封装vo对象放入pageResult
        List<MovementsVo> movementsVos = new ArrayList<>();
        for (Movement movement : movements) {
            MovementsVo m = MovementsVo.init(userInfo, movement);
            movementsVos.add(m);
        }
        //5、封装并返回
        return new PageResult(page, pageSize, 0l, movementsVos);
    }

    /**
     * 获取好友动态
     *
     * @param page
     * @param pageSize
     * @return
     */
    public PageResult getFriend(Integer page, Integer pageSize) {
        //1、获取用户id
        Long userId = UserHolder.getUserId();
        //2、查询朋友动态
        List<Movement> movements = movementApi.getByFriend(userId, page, pageSize);
        return getPageResult(page, pageSize, movements);
    }


    /**
     * 查询多个用户动态详细信息公共方法
     *
     * @param page
     * @param pageSize
     * @param movements
     * @return
     */
    private PageResult getPageResult(Integer page, Integer pageSize, List<Movement> movements) {
        //3、判断是否有动态，没有的话直接返回空
        if (CollUtil.isEmpty(movements)) {
            return new PageResult();
        }

        //4、查询用户信息(先获取查询到的用户ids)
        List<Long> ids = CollUtil.getFieldValues(movements, "userId", Long.class);
        Map<Long, UserInfo> map = userInfoApi.selectByIds(ids, new RecommendUserDto());
        //5、封装vo对象放入pageResult
        List<MovementsVo> m = new ArrayList<>();
        for (Movement movement : movements) {
            if (map.get(movement.getUserId()) != null) {
                MovementsVo vo = MovementsVo.init(map.get(movement.getUserId()), movement);

                //更改返回前端的喜欢和点赞标识
                String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId();
                String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
                String hashKey2 = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();

                if (redis.opsForHash().hasKey(key, hashKey)) {
                    vo.setHasLiked(1);
                }
                if (redis.opsForHash().hasKey(key, hashKey2)) {
                    vo.setHasLoved(1);
                }
                m.add(vo);
            }
        }
        //6、封装并返回数据
        PageResult pageResult = new PageResult(page, pageSize, 0l, m);
        return pageResult;
    }

    /**
     * 推荐列表动态展示(根据推荐的pids进行查询，pids在redis中保存着)
     *
     * @param page
     * @param pageSize
     * @return
     */
    public PageResult recommend(Integer page, Integer pageSize) {

        //1、查询redis中的pids
        String redisKey = Constants.MOVEMENTS_RECOMMEND + UserHolder.getUserId();
        String s = redis.opsForValue().get(redisKey);
        //2、判断pids是否有值(有值说明有推荐，通过pids查询，如果没有就随机给安排几个)
        List<Movement> movements = new ArrayList<>();

        if (StringUtils.isEmpty(s)) {
            //如果没有
            movements = movementApi.findByRandom(pageSize);
        } else {
            //如果有处理ids模拟分页
            String[] split = s.split(",");
            if ((page - 1) * pageSize < split.length) {
                //如果条件满足说明满足分页条件，用stream处理模仿分页并收集集合
                List<Long> pids = Arrays.stream(split).skip((page - 1) * pageSize).limit(pageSize)
                        .map(e -> Long.valueOf(e))//这一步表示处理类型(String->Long)
                        .collect(Collectors.toList());
                //通过pids查询动态
                movements = movementApi.findByPids(pids);
            }

        }
        //3、调用抽取的getPageResult()方法(查询多个用户的动态详细信息)
        PageResult pageResult = getPageResult(page, pageSize, movements);
        //4、返回数据
        return pageResult;
    }

    /**
     * 通过动态id查询动态
     *
     * @param id
     * @return
     */
    public MovementsVo getByMovementId(String id) {
        Movement movement = movementApi.findByMovementId(id);
        MovementsVo vo = new MovementsVo();
        if (movement == null) {
            return vo;
        }
        UserInfo userInfo = userInfoApi.findById(movement.getUserId());
        vo = MovementsVo.init(userInfo, movement);
        return vo;
    }

    /**
     * 点赞
     *
     * @param movementId
     * @return
     */
    public Integer like(String movementId) {
        //1、查询用户id
        Long userId = UserHolder.getUserId();
        CommentType like = CommentType.LIKE;
        //2、调用服务判断是否点赞
        boolean b = commentApi.isOrNo(new ObjectId(movementId), userId, like);
        if (b) {
            //如果true说明已经点过赞了，抛出异常
            throw new BusinessException(ErrorResult.likeError());
        }
        //3、没点赞构建comment保存点赞信息并更新动态表中的数量
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(CommentType.LIKE.getType());
        comment.setUserId(userId);
        comment.setCreated(System.currentTimeMillis());
        Integer likeCount = commentApi.send(comment);
        //4、把已经点赞的信号放在redis中，用于前端是否展示点赞标识
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
        redis.opsForHash().put(key, hashKey, "1");//1表示已经点赞
        //5、返回新的点赞数量供前端展示
        return likeCount;
    }

    /**
     * 取消点赞
     *
     * @param movementId
     * @return
     */
    public Integer disLike(String movementId) {
        Long userId = UserHolder.getUserId();
        CommentType like = CommentType.LIKE;
        //1、判断是否点赞
        boolean b = commentApi.isOrNo(new ObjectId(movementId), userId, like);
        //2、没点赞抛出异常
        if (!b) {
            //如果false说明已经没点过赞，抛出异常
            throw new BusinessException(ErrorResult.disLikeError());
        }
        //3、创建comment对象并调用服务删除评论数据获取最新点赞数量
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(CommentType.LIKE.getType());
        comment.setUserId(userId);
        Integer likeCount = commentApi.delete(comment);
        //4、删除redis中的点赞信号
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
        redis.opsForHash().delete(key, hashKey);
        //5、返回新的点赞数量
        return likeCount;
    }


    /**
     * 喜欢
     *
     * @param movementId
     * @return
     */
    public Integer love(String movementId) {
        //1、查询用户id
        Long userId = UserHolder.getUserId();
        CommentType love = CommentType.LOVE;
        //2、调用服务判断是否喜欢
        boolean b = commentApi.isOrNo(new ObjectId(movementId), userId, love);
        if (b) {
            //如果true说明已经喜欢过了，抛出异常
            throw new BusinessException(ErrorResult.loveError());
        }
        //3、没喜欢构建comment保存点赞信息并更新动态表中的数量
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(CommentType.LOVE.getType());
        comment.setUserId(userId);
        comment.setCreated(System.currentTimeMillis());
        Integer loveCount = commentApi.send(comment);
        //4、把已经点赞的信号放在redis中，用于前端是否展示喜欢标识
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
        redis.opsForHash().put(key, hashKey, "1");//1表示已经喜欢
        //5、返回新的点赞数量供前端展示
        return loveCount;
    }

    /**
     * 取消喜欢
     *
     * @param movementId
     * @return
     */
    public Integer disLove(String movementId) {
        Long userId = UserHolder.getUserId();
        CommentType love = CommentType.LOVE;
        //1、判断是否点喜欢
        boolean b = commentApi.isOrNo(new ObjectId(movementId), userId, love);
        //2、没有喜欢抛出异常
        if (!b) {
            //如果false说明已经没喜欢，抛出异常
            throw new BusinessException(ErrorResult.disloveError());
        }
        //3、创建comment对象并调用服务删除评论数据获取最新点赞数量
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(CommentType.LOVE.getType());
        comment.setUserId(userId);
        Integer loveCount = commentApi.delete(comment);
        //4、删除redis中的点赞信号
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
        redis.opsForHash().delete(key, hashKey);
        //5、返回新的点赞数量
        return loveCount;
    }

    /**
     * 展示最新访客(5条)
     *
     * @return
     */
    public List<VisitorsVo> visitors() {
        //1、查询redis获取上一次查询访客的时间
        String keys = Constants.VISITORS_USER;
        String hashKey = String.valueOf(UserHolder.getUserId());
        String time = (String) redis.opsForHash().get(keys, hashKey);
        Long date = StringUtils.isEmpty(time) ? null : Long.valueOf(time);
        //2、根据上一次查看访客的时间获取最新的访客
        List<Visitors> list = visitorsApi.getNewUser(UserHolder.getUserId(), date);
        //3、获取访客的信息
        List<VisitorsVo> vos = new ArrayList<>();
        if (!CollUtil.isEmpty(list)) {
            List<Long> ids = CollUtil.getFieldValues(list, "visitorUserId", Long.class);
            Map<Long, UserInfo> map = userInfoApi.selectByIds(ids, new RecommendUserDto());
            for (Visitors visitors : list) {
                UserInfo userInfo = map.get(visitors.getVisitorUserId());
                if (userInfo != null) {
                    //4、封装vo对象并返回
                    VisitorsVo init = VisitorsVo.init(userInfo, visitors);
                    vos.add(init);
                }
            }
        }
        return vos;
    }
}
